package cn.edu.nit.sys.service.impl;

import cn.edu.nit.sys.entity.*;
import cn.edu.nit.sys.mapper.ClazzMapper;
import cn.edu.nit.sys.mapper.CourseMapper;
import cn.edu.nit.sys.mapper.EquipMapper;
import cn.edu.nit.sys.mapper.SubjectMapper;
import cn.edu.nit.sys.service.CourseService;
import cn.edu.nit.sys.utils.R;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author 罗文斌
 * @Date 2023/3/21
 * @Version 1.0.0
 */
@Service
@Slf4j
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements CourseService {

    @Autowired
    private SubjectMapper subjectMapper;

    @Autowired
    private ClazzMapper clazzMapper;

    @Autowired
    private EquipMapper equipMapper;

    @Override
    public R arrangeCourse(Course course) {
        String[] weeks = course.getWeek().split(",");
        Calendar instance = Calendar.getInstance();
        int year = instance.get(Calendar.YEAR);
        String yearStr = year + "-" + (year + 1) + "学年";
        int rs = 0;
        for(int i = 0; i < weeks.length; i++) {
            Course course1 = new Course();
            course1.setEquipId(course.getEquipId());
            course1.setSubjectId(course.getSubjectId());
            course1.setDay(course.getDay());
            course1.setTime(course.getTime());
            course1.setWeek(weeks[i]);
            course1.setYear(yearStr);
            rs += baseMapper.insert(course1);
        }
        return rs == weeks.length ? R.ok("排课成功") : R.error("排课失败");
    }

    @Override
    @Transactional
    public R autoArrangeCourse(Long start) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(new Date(start));
        int year = instance.get(Calendar.YEAR);
        String yearStr = "";
        if(instance.get(Calendar.MONTH) < 6) {
            yearStr = (year - 1) + "-" + year + "-2";  // 下学期
        }else {
            yearStr = year + "-" + (year + 1) + "-1";  // 上学期
        }
        List<Subject> allSubject = subjectMapper.getAllSubject(yearStr);
        List<Equip> allEquip = equipMapper.getAllEquip();
        for(Subject subject : allSubject) {
            if(baseMapper.isArrange(subject.getId()).size() > 0) {    // 当前课程已排课
                continue;
            }
            String[] courseWeeks = getCourseWeek(subject.getDuration(), subject.getTimeStr()).split(",");
            List<Equip> roomList = getCourseRoom(subject, allEquip);
            for(String week : courseWeeks) {
                setRoom(subject, week, roomList, start);
            }
        }
        return R.ok("排课完成");
    }

    @Override
    public R getCourseList(Page<Course> page, String siftName, String siftTime) {
        Page<Course> courseList = baseMapper.getCourseList(page, siftName, siftTime);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("total", courseList.getTotal());
        jsonObject.put("list", courseList.getRecords());
        return R.ok(jsonObject);
    }

    @Override
    public R getPcList(String uid, String siftTime) {
        List<Map<String, String>> pcList = baseMapper.getPcList(uid, siftTime);
        return R.ok(pcList);
    }

    @Override
    public R getStudentCourse(String id, String start) {
        List<Map<String, Object>> rs = dealCourse(start, "0", id);
        return R.ok(rs);
    }

    @Override
    public R getTeacherCourse(String id, String time) {
        List<Map<String, Object>> rs = dealCourse(time, "1", id);
        return R.ok(rs);
    }

    @Override
    public R getYearList() {
        List<String> yearList = baseMapper.getYearList();
        return R.ok(yearList);
    }

    @Override
    public R getCourseForTeacher(String id, String siftTime) {
        List<Map<String, String>> courseForTeacher = baseMapper.getCourseForTeacher(id, siftTime);
        return R.ok(courseForTeacher);
    }

    /**
     * 教室、课程、上课时间
     * @param subject   课程
     * @param week  上课周
     * @param roomList  教室数据集
     */
    private void setRoom(Subject subject, String week, List<Equip> roomList, Long start) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(new Date(start));
        int year = instance.get(Calendar.YEAR);
        String yearStr = "";
        if(instance.get(Calendar.MONTH) < 6) {
            yearStr = (year - 1) + "-" + year + "-2";  // 下学期
        }else {
            yearStr = year + "-" + (year + 1) + "-1";  // 上学期
        }
        int i = new Random().nextInt(roomList.size());
        Equip room = roomList.get(i);
        int rate = new Random().nextInt(9);
        int day = new Random().nextInt(7);  // 随机生成上课时间-周一-周日
        int time = new Random().nextInt(5); // 随机生成上课时间-第一二三四五节
        // 降低课程安排在周末概率
        while(rate > 1 && day > 4) {
            day = new Random().nextInt(7);
        }
        // 降低课程安排在晚上概率
        while(rate > 1 && time == 4) {
            time = new Random().nextInt(5);
        }
        if(baseMapper.isExist(week, day, time, room.getId()).size() == 0 &&
                baseMapper.isCourse(week, day, time, subject.getId()).size() == 0) {
            Course cou = new Course();
            cou.setSubjectId(subject.getId());
            cou.setEquipId(room.getId().toString());
            cou.setWeek(week);
            cou.setDay(Integer.toString(day));
            cou.setTime(Integer.toString(time));
            cou.setYear(yearStr);
            cou.setTeacher_id(subject.getTeacherId());
            baseMapper.insert(cou);
        }else {
            setRoom(subject, week, roomList, start);
        }
    }

    /**
     * 获取上课周
     * @param duration 总课时
     * @param week 上课周
     */
    private String getCourseWeek(int duration, String week) {
        int total = duration / 2;
        String[] split = week.split(",");
        if(total > split.length){         // 部分周存在多节课
            for(int i = 0; i < total - split.length; i++) {
                int randomWeek = new Random().nextInt(split.length);   // 随机某周至少一节
                week += "," + split[randomWeek];
            }
        }
        return week;
    }

    /**
     * 获取上课教室
     * @param subject   当前课程
     * @param allEquip  空闲教室
     * @return
     */
    private List<Equip> getCourseRoom(Subject subject, List<Equip> allEquip) {
        int volume = clazzMapper.getCurSubjectVolume(subject.getClazz().split(","), subject.getGrade());
        List<Equip> equips = compareVolume(volume, allEquip);
        return equips;
    }

    /**
     * 座位数满足上课人数的教室
     * @param clazzVolume  上课人数
     * @param roomList  教室数据
     * @return
     */
    private List<Equip> compareVolume(int clazzVolume, List<Equip> roomList) {
        List<Equip> list = new ArrayList<>();
        // 座位数满足上课人数的教室
        for(Equip equip : roomList) {
            if(equip.getVolume() >= clazzVolume) {
                list.add(equip);
            }
        }
        // 按座位数小到大排序
        list.sort(new Comparator<Equip>() {
            @Override
            public int compare(Equip o1, Equip o2) {
                return o1.getVolume() - o2.getVolume();
            }
        });
        return list;
    }

    /**
     * 获取课程表
     * @param time  当前学期开始时间
     * @param type  0：学生；1：老师
     * @param id    用户ID
     * @return
     */
    private List<Map<String, Object>> dealCourse(String time, String type, String id) {
        long parseLong = Long.parseLong(time);
        Date date = new Date(parseLong);
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        String year = "";
        int x = instance.get(Calendar.YEAR);
        if(instance.get(Calendar.MONTH) < 6) {
            year = x - 1 + "-" + x + "-2";
        }else {
            year = x + "-" + (x + 1) + "-1";
        }
        List<Map<String, Object>> dataList = new ArrayList<>();
        if("0".equals(type)) {
            dataList = baseMapper.getStudentCourse(id, year);
        }else if("1".equals(type)) {
            dataList = baseMapper.getTeacherCourse(id, year);
        }
        List<Map<String, Object>> rs = new ArrayList<>();
        for(Map<String, Object> map : dataList) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            int week = Integer.parseInt(map.get("week").toString());
            int day = Integer.parseInt(map.get("day").toString());
            calendar.add(Calendar.DAY_OF_YEAR, (week - 1) * 7 + day);
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            map.put("date", format.format(calendar.getTime()));
            rs.add(map);
        }
        return rs;
    }
}
